package cn.example.demo.common.secure.context;

import cn.example.demo.common.dictionary.AuthCenterBaseInfo;
import cn.example.demo.common.secure.dto.LoginUser;
import cn.example.demo.common.secure.exception.LoginException;
import cn.example.demo.modules.sys.model.entity.SysDepartment;
import cn.example.demo.modules.sys.model.entity.SysRole;
import cn.example.demo.modules.sys.model.entity.SysUser;
import cn.example.demo.modules.sys.service.UserService;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.github.benmanes.caffeine.cache.Cache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.annotation.Resource;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 登录用户操作接口实现类
 *
 * @author Lizuxian
 * @create 2022/3/3 0:27
 */
@Service
public class LoginUserApiImpl implements LoginUserApi {
    private final PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    @Autowired
    private AuthCenterBaseInfo authCenterBaseInfo;

    @Resource(name = "sessionCache")
    private Cache<String, Object> sessionCache;
    @Resource(name = "tokenCache")
    private Cache<Integer, String> tokenCache;

    @Resource
    private UserService userService;

    @Override
    public LoginUser getCurrentLoginUser() {
        return (LoginUser) RequestContextHolder.currentRequestAttributes().getAttribute(authCenterBaseInfo.getTokenName(), RequestAttributes.SCOPE_REQUEST);
    }

    @Override
    public LoginUser usernamePasswordLogin(String username, String password) {
        // 1.查询用户
        SysUser user = userService.findUserByUsername(username);

        // 2.密码验证
        if (user != null && passwordEncoder.matches(password, user.getPassword())) {
            // 3.封装会话信息
            LoginUser loginUser = new LoginUser();
            BeanUtil.copyProperties(user, loginUser, true);
            // 4.权限数据
            fillRoleAndOrgInfo(loginUser, user.getUserId());
            // 5.生成 Token
            String token = UUID.randomUUID().toString();
            // 6.保存数据到服务端本地缓存中
            tokenCache.put(user.getUserId(), token);
            sessionCache.put(token, loginUser);

            return loginUser;
        }

        // 登录异常
        throw LoginException.usernameOrPasswordNotCorrect();
    }

    @Override
    public boolean refreshUserSessionByUserId(Integer userId) {
        String token = tokenCache.getIfPresent(userId);

        if (StrUtil.isNotBlank(token)) {
            LoginUser loginUser = (LoginUser) sessionCache.getIfPresent(token);
            if (loginUser != null) {
                // 更新权限数据
                fillRoleAndOrgInfo(loginUser, userId);
                // 更新会话数据到服务端本地缓存中
                sessionCache.put(token, loginUser);

                return true;
            }
        }

        return false;
    }

    /**
     * 填充用户角色，组织等权限数据
     *
     * @param loginUser
     * @param userId
     */
    private void fillRoleAndOrgInfo(LoginUser loginUser, Integer userId) {
        // 查询用户角色
        List<SysRole> roles = userService.getAllBindRolesByUserId(userId);
        // 查询用户机构
        SysDepartment org = userService.getBindOrgByUserId(userId);

        loginUser.setRoleIds(roles.stream().map(SysRole::getRoleId).collect(Collectors.toSet()));
        loginUser.setDataScopes(roles.stream().map(SysRole::getDataScope).collect(Collectors.toSet()));

        if (org != null) {
            loginUser.setDeptId(org.getNode());
            loginUser.setDept(org.getDeptName());
        }
    }
}
